/**
 * Copyright (C) 2011 The Android Open Source Project 
 * Emial : guoyil199@163.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package com.db;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;


/**
 * @author Administrator
 * @Email guoyil199@163.com
 * @version V1.0
 * @Date 2015年5月29日 下午4:26:52
 * @Title <pre>
 * Data Set 
 * </pre>
 * @Description <pre>
 * todo
 * </pre>
 */
public class SqliteDataSet {
	private static final String TAG="SqliteDataSet";

	private Context mCtx;
	private SQLiteHelper dbHelper;
	private SQLiteDatabase rdb;
	private SQLiteDatabase wdb;

	public SqliteDataSet(Context ctx) {
		this.mCtx = ctx;
		dbHelper = SQLiteHelper.builder().beginConfig()
		// .onCreateCallback(onCreateCallback)
		// .foreignKey(true)
				.endConfig()
				// .tables(TABLES)
				// .tableNames(TABLE_NAMES)
				// .version(SQLITE_VERSION)
				.build(mCtx);
		wdb = dbHelper.getWritableDatabase();
		rdb = dbHelper.getReadableDatabase();
	}

	/**
	 * @Description <pre>
	 * 关闭数据库
	 * </pre>
	 * @return void
	 */
	public void close() {
		if (rdb.isOpen())
			rdb.close();
		if(wdb.isOpen()){
			wdb.close();
		}
		if (dbHelper != null)
			dbHelper.close();
	}

	/**
	 * 插入数据
	 * @param sql
	 *            执行更新操作的sql语句
	 * @param bindArgs
	 *            sql语句中的参数,参数的顺序对应占位符顺序
	 * @return result 返回新添记录的行号，与主键id无关
	 */
	public long insertBySql(String sql, String[] bindArgs) throws SQLiteException {
		long result = 0;
		if (wdb.isOpen()) {
			SQLiteStatement statement = wdb.compileStatement(sql);
			if (bindArgs != null) {
				int size = bindArgs.length;
				for (int i = 0; i < size; i++) {
					// 将参数和占位符绑定，对应
					statement.bindString(i + 1, bindArgs[i]);
				}
				result = statement.executeInsert();
				statement.close();
			}
		} else {
			Log.i(TAG,"insertBySql, 数据库已关闭");
		}
		return result;
	}

	/**
	 * 插入数据
	 * @param table
	 *            表名
	 * @param values
	 *            要插入的数据
	 * @return result 返回新添记录的行号，与主键id无关
	 */
	public long insert(String table, ContentValues values) {
		long result = 0;
		if (wdb.isOpen()) {
			result = wdb.insert(table, null, values);
		}
		return result;
	}

	/**
	 * 更新数据
	 * 
	 * @param sql
	 *            执行更新操作的sql语句
	 * @param bindArgs
	 *            sql语句中的参数,参数的顺序对应占位符顺序
	 */
	public void updateBySql(String sql, String[] bindArgs) throws Exception {
		if (wdb.isOpen()) {
			SQLiteStatement statement = wdb.compileStatement(sql);
			if (bindArgs != null) {
				int size = bindArgs.length;
				for (int i = 0; i < size; i++) {
					statement.bindString(i + 1, bindArgs[i]);
				}
				statement.execute();
				statement.close();
			}
		} else {
			Log.i(TAG, "updateBySql 数据库已关闭");
		}
	}

	/**
	 * 更新数据
	 * @param table
	 *            表名
	 * @param values
	 *            表示更新的数据
	 * @param whereClause
	 *            表示SQL语句中条件部分的语句
	 * @param whereArgs
	 *            表示占位符的值
	 * @return
	 */
	public int update(String table, ContentValues values,
			String whereClause, String[] whereArgs) {
		int result = 0;
		if (wdb.isOpen()) {
			result = wdb.update(table, values, whereClause,
					whereArgs);
		}
		return result;
	}

	/**
	 * 删除数据
	 * 
	 * @param sql
	 *            执行更新操作的sql语句
	 * @param bindArgs
	 *            sql语句中的参数,参数的顺序对应占位符顺序
	 */
	public void deleteBySql(String sql, String[] bindArgs) throws Exception {
		if (wdb.isOpen()) {
			SQLiteStatement statement = wdb.compileStatement(sql);
			if (bindArgs != null) {
				int size = bindArgs.length;
				for (int i = 0; i < size; i++) {
					statement.bindString(i + 1, bindArgs[i]);
				}
				Method[] mm = statement.getClass().getDeclaredMethods();
				for (Method method : mm) {
					Log.i(TAG, "deleteBySql"+method.getName());
					/**
					 * 反射查看是否能获取executeUpdateDelete方法 查看源码可知
					 * executeUpdateDelete是public的方法，但是好像被隐藏了所以不能被调用，
					 * 利用反射貌似只能在root以后的机器上才能调用，小米是可以，其他机器却不行，所以还是不能用。
					 */
				}
				statement.execute();
				statement.close();
			}
		} else {
			Log.i(TAG, "deleteBySql 数据库已关闭");
		}
	}

	/**
	 * 删除数据
	 * 
	 * @param table
	 *            表名
	 * @param whereClause
	 *            表示SQL语句中条件部分的语句
	 * @param whereArgs
	 *            表示占位符的值
	 * @return
	 */
	public int delete(String table, String whereClause, String[] whereArgs) {
		int result = 0;
		if (wdb.isOpen()) {
			result = wdb.delete(table, whereClause, whereArgs);
		}
		return result;
	}

	/**
	 * 查询数据
	 * 
	 * @param searchSQL
	 *            执行查询操作的sql语句
	 * @param selectionArgs
	 *            查询条件
	 * @return 返回查询的游标，可对数据自行操作，需要自己关闭游标
	 */
	public Cursor query(String sql, String[] selectionArgs){
		if (rdb.isOpen()) {
			try {
				Cursor cursor = rdb.rawQuery(sql, selectionArgs);
				if (cursor != null) {
					cursor.moveToFirst();
				}
				return cursor;	
			} catch (Exception e) {
				Log.i(TAG, "query "+e.getMessage(),e);
			}
			
		}
		return null;
	}

	/**
	 * 查询数据
	 * @param sql
	 *            执行查询操作的sql语句
	 * @param selectionArgs
	 *            查询条件
	 * @param object
	 *            Object的对象
	 * @return List<T> 返回查询结果
	 */
	public <T> List<T> queryToList(String sql, String[] selectionArgs,T t){
		try {
			List<T> mList = new ArrayList<T>();
			if (rdb.isOpen()) {
				Cursor cursor = rdb.rawQuery(sql, selectionArgs);
				Field[] f;
				if (cursor != null && cursor.getCount() > 0) {
					while (cursor.moveToNext()) {
						f = t.getClass().getDeclaredFields();
						for (int i = 0; i < f.length; i++) {//JavaBean 设值
							invokeField(t, f[i].getName(),cursor.getString(cursor.getColumnIndex(f[i].getName())));
						}
						mList.add(t);
					}
				}
				cursor.close();
			} else {
				Log.i(TAG, " queryToList 数据库已关闭");
			}
		} catch (Exception e) {
			Log.e(TAG, " queryToList "+e.getMessage(),e);
		}
		return null;
	}

	/**
	 * 查询数据
	 * @param sql
	 *            执行查询操作的sql语句
	 * @param selectionArgs
	 *            查询条件
	 * @param object
	 *            Object的对象
	 * @return List<Map<String, Object>> 返回查询结果
	 */
	@SuppressWarnings("unchecked")
	public <T> List<Map<String,T>> queryToMap(String sql,String[] selectionArgs, T t){
		try {
			List<Map<String, T>> mList = new ArrayList<Map<String, T>>();
			if (rdb.isOpen()) {
				Cursor cursor = rdb.rawQuery(sql, selectionArgs);
				Field[] f;
				Map<String, T> map;
				if (cursor != null && cursor.getCount() > 0) {
					while (cursor.moveToNext()) {
						map = new HashMap<String, T>();
						f = t.getClass().getDeclaredFields();
						for (int i = 0; i < f.length; i++) {
							T v=(T) cursor.getString(cursor.getColumnIndex(f[i].getName()));
							map.put(f[i].getName(), v);
						}
						mList.add(map);
					}
				}
				cursor.close();
			} else {
				Log.i(TAG, "queryToMap 数据库已关闭");
			}
			return mList;
		} catch (Exception e) {
			Log.e(TAG, " queryToMap "+e.getMessage(),e);
		}
		return null;
	}

	/**
	 * 反射set方法
	 * @param objectClass
	 * @param fieldName
	 * @return
	 */
	public <T> Method getSetMethod(Class<T> t, String fieldName) {
		try {
			Class<?>[] parameterTypes = new Class[1];
			Field field = t.getDeclaredField(fieldName);
			parameterTypes[0] = field.getType();
			StringBuffer sb = new StringBuffer();
			sb.append("set");
			sb.append(fieldName.substring(0, 1).toUpperCase());
			sb.append(fieldName.substring(1));
			Method method = t.getMethod(sb.toString(), parameterTypes);
			return method;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 反射get方法
	 * @param t
	 * @param fieldName
	 * @return
	 */
	public <T> Method getGetMethod(Class<T> t, String fieldName) {
		try {
			Class<?>[] parameterTypes = new Class[1];
			Field field = t.getDeclaredField(fieldName);
			parameterTypes[0] = field.getType();
			StringBuffer sb = new StringBuffer();
			sb.append("get");
			sb.append(fieldName.substring(0, 1).toUpperCase());
			sb.append(fieldName.substring(1));
			Method method = t.getMethod(sb.toString()/*, parameterTypes*/);
			//method.invoke(parameterTypes);
			return method;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	

	/**
	 * 执行 Public属性
	 * @param obj
	 * @param fieldName
	 * @param value
	 * @return void
	 */
	private <T> void invokeField(T t, String fieldName, Object value) {
		// Method method = getSetMethod(obj.getClass(), fieldName);
		try {
			Field field = t.getClass().getField(fieldName);
			if (field != null) {
				field.setAccessible(true);
				// Class fieldType = field.getType();
				field.set(t, value);
			}
		} catch (Exception e) {
			Log.e(TAG,e.getMessage(),e);
		}

	}
	
	
	/**
	 * 执行set方法
	 * @param object
	 *            执行对象
	 * @param fieldName
	 *            属性
	 * @param value
	 *            值
	 */
	public <T> void invokeSet_(T t, String fieldName, Object value) {
		Method method = getSetMethod(t.getClass(), fieldName);
		try {
			method.invoke(t, new Object[] { value });
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
